package com.sz.netty.consumer;

import com.sz.netty.entity.DtuFtpMessageDetail;
import com.sz.netty.entity.DtuFtpMessageLog;
import com.sz.netty.entity.DtuTransportInfo;
import com.sz.netty.service.DeviceCommandService;
import com.sz.netty.service.DtuFtpMessageDetailService;
import com.sz.netty.service.DtuFtpMessageLogService;
import com.sz.netty.util.TransportEventLogger;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * Consumer for processing expired messages from RabbitMQ dead letter queues
 */
@Slf4j
@Component
public class ExpiredMessageConsumer {
    
    @Autowired
    private DtuFtpMessageDetailService dtuFtpMessageDetailService;
    
    @Autowired
    private DtuFtpMessageLogService dtuFtpMessageLogService;
    
    @Autowired
    private DeviceCommandService deviceCommandService;
    
    /**
     * Listen to DTU record dead letter queue and process expired records
     * When a record expires, send "000" message to the device
     * 
     * @param recordId the ID of the expired record
     */
    @RabbitListener(queues = "dtu.record.dlq")
    public void processExpiredRecord(Long recordId) {
        try {
            log.info("Received expired record ID from RabbitMQ DLQ: {}", recordId);
            
            // Get the record from database
            DtuFtpMessageDetail messageDetail = dtuFtpMessageDetailService.getById(recordId);
            if (messageDetail == null) {
                log.warn("Expired record not found for ID: {}", recordId);
                return;
            }
            
            String deviceId = getDeviceIdFromMessageDetail(messageDetail);
            if (deviceId == null) {
                log.warn("Device ID not found for expired record ID: {}", recordId);
                return;
            }
            
            // Send "000" message to device
            sendZeroMessageToDevice(deviceId);
            
            log.info("Processed expired record ID {} and sent '000' message to device {}", recordId, deviceId);
            
        } catch (Exception e) {
            log.error("Error processing expired record ID {}: {}", recordId, e.getMessage(), e);
        }
    }
    
    /**
     * Listen to DTU transport dead letter queue and process expired transports
     * When a transport expires, send "000" message to the device
     * 
     * @param transportInfo the expired transport info
     */
    @RabbitListener(queues = "dtu.transport.dlq")
    public void processExpiredTransport(DtuTransportInfo transportInfo) {
        try {
            log.info("Received expired transport info from RabbitMQ DLQ: {}", transportInfo.getId());
            
            String deviceId = transportInfo.getDtuNumber();
            if (deviceId == null) {
                log.warn("Device ID not found for expired transport ID: {}", transportInfo.getId());
                return;
            }
            
            // Send "000" message to device
            sendZeroMessageToDevice(deviceId);
            
            log.info("Processed expired transport ID {} and sent '000' message to device {}", 
                    transportInfo.getId(), deviceId);
            
        } catch (Exception e) {
            log.error("Error processing expired transport ID {}: {}", transportInfo.getId(), e.getMessage(), e);
        }
    }
    
    /**
     * Extract device ID from message detail
     * 
     * @param messageDetail the message detail
     * @return device ID or null if not found
     */
    private String getDeviceIdFromMessageDetail(DtuFtpMessageDetail messageDetail) {
        try {
            // Get device ID from the associated message log
            Long ftpMessageLogId = messageDetail.getFtpMessageLogId();
            if (ftpMessageLogId == null) {
                log.warn("FTP message log ID is null for message detail ID: {}", messageDetail.getId());
                return null;
            }
            
            // Get the message log to extract device ID
            DtuFtpMessageLog messageLog = dtuFtpMessageLogService.getById(ftpMessageLogId);
            if (messageLog == null) {
                log.warn("Message log not found for ID: {}, skipping device ID extraction", ftpMessageLogId);
                return null;
            }
            
            String deviceId = messageLog.getDtuNumber();
            if (deviceId == null || deviceId.isEmpty()) {
                log.warn("Device ID is null or empty in message log ID: {}", ftpMessageLogId);
                return null;
            }
            
            return deviceId;
        } catch (Exception e) {
            log.error("Error extracting device ID from message detail: {}", e.getMessage(), e);
            return null;
        }
    }
    
    /**
     * Send "000" message to device using the same mechanism as endpoint success messages
     * 
     * @param deviceId the device ID
     */
    private void sendZeroMessageToDevice(String deviceId) {
        try {
            if (deviceCommandService != null && deviceCommandService.isDeviceConnected(deviceId)) {
                String message = "000"; // Zero message for expired messages
                
                // Try to send the command with acknowledgment waiting and retry logic
                boolean commandSent = false;
                int retryCount = 0;
                final int maxRetries = 6;
                
                while (!commandSent && retryCount < maxRetries) {
                    if (retryCount > 0) {
                        // Add a delay between retries
                        try {
                            Thread.sleep(6000); // Wait 6 seconds between retries
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            break;
                        }
                        log.debug("Retrying to send zero message '{}' to device {} (attempt {})", 
                                message, deviceId, retryCount + 1);
                    }
                    
                    // Before sending the new command, clear the previous display state
                    // This prevents visual artifacts or incorrect displays
                    clearDeviceDisplay(deviceId);
                    
                    // Add a delay after clearing display before sending the new command
                    try {
                        Thread.sleep(300);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                    
                    // Send command and wait for acknowledgment
                    commandSent = deviceCommandService.sendRemoteDisplayContentWithAck(deviceId, message);
                    retryCount++;
                }
                
                if (commandSent) {
                    log.info("Sent zero message '{}' to device {} (acknowledged)", message, deviceId);
                } else {
                    log.warn("Failed to send zero message '{}' to device {} after {} attempts (no acknowledgment)", 
                            message, deviceId, maxRetries);
                }
                
                // Log device command event
                TransportEventLogger.logDeviceCommandEvent(deviceId, message, "Expired message notification");
            } else {
                log.warn("Device {} is not connected or device command service is not available", deviceId);
            }
        } catch (Exception e) {
            log.error("Error sending zero message to device {}: {}", deviceId, e.getMessage(), e);
        }
    }
    
    /**
     * Clear the device display by sending a blank command
     * This prevents visual artifacts when switching between different display commands
     * 
     * @param deviceId the device ID
     */
    private void clearDeviceDisplay(String deviceId) {
        try {
            log.debug("Clearing display for device {}", deviceId);
            
            // Send a blank display command to clear the previous state
            // Using "   " (three spaces) to clear the display
            String blankCommand = "   "; // Three spaces
            
            // Send the blank command
            boolean result = deviceCommandService.sendRemoteDisplayContent(deviceId, blankCommand);
            
            if (result) {
                log.debug("Successfully sent display clear command to device {}", deviceId);
            } else {
                log.warn("Failed to send display clear command to device {}", deviceId);
            }
            
            // Add a delay after sending the clear command
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        } catch (Exception e) {
            log.error("Error clearing display for device {}: {}", deviceId, e.getMessage(), e);
        }
    }
}